# browserify for webpack users

There's been a strange explosion in misinformation about browserify recently,
particularly in comparisons to webpack.

Generally speaking, most of this confusion stems from how webpack is more
willing to pull features into its core to ease discoverability while browserify
is more likely to push features out to userland instead.

I think that longer-term, separability has more benefits from a maintenance and
experimentation perspective, but that doesn't mean that you can't do pretty much
everything webpack can do in the browserify ecosystem. It just means that there
might be several different ways of doing that task to serve different use-cases.
[Diversity is good!](http://www.faqs.org/docs/artu/ch01s06.html#id2879078).
Diversity means that you can choose an approach that more closely matches the
trade-offs that you need, but you might need to put in more work to evaluate the
different options.

Hopefully this document will help somewhat with finding options to evaluate.

# bundle splitting

Webpack, to its credit, provided some useful ideas about how to handle splitting
bundles up into multiple pages automatically.
However, this idea was quickly taken up in browserify using the plugin API into
[factor-bundle](https://npmjs.org/package/factor-bundle).

If you want to, you can still split up bundles using `-x` and `-r`, but for
creating multi-page bundles, it's pretty easy to automate that away with
factor-bundle in a very similar way.
In both cases for browserify and webpack you will end up with 2 `<script>` tags
you can include on each page.

To split up common assets from entry points `x.js` and `y.js` into bundles
`bundle/x.js` and `bundle/y.js` with a common bundle `bundle/common.js`, in
webpack you can edit the webpack config with:

```
var webpack = require('webpack');
module.exports = {
    entry: {
        x: "./x.js",
        y: "./y.js",
    },
    output: {
        path: "bundle",
        filename: "[name].js"
    },
    plugins: [
        new webpack.optimize.CommonsChunkPlugin("common.js")
    ]
};
```

or in browserify with [factor-bundle](https://npmjs.org/package/factor-bundle)
you can just do:

``` sh
browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o y.js ] \
  -o bundle/common.js
```

or from the API, that would be:

``` js
var browserify = require('browserify');
var fs = require('fs');

var files = [ 'x.js', 'y.js' ];
var b = browserify(files);
b.plugin('factor-bundle', { outputs: [ 'bundle/x.js', 'bundle/y.js' ] });
b.bundle().pipe(fs.createWriteStream('bundle/common.js'));
```

To load bundles asynchronously you can easily whip something up with
[xhr](https://npmjs.org/package/xhr) and eval() or for a more automatic option
there's
[partition bundle](https://github.com/substack/browserify-handbook#partition-bundle).

# stdout by default

This is a small thing, but writing to stdout by default can be very handy.

Instead of how in webpack you do:

``` sh
webpack main.js bundle.js
````

In browserify you can also write to a file without using the shell:

``` sh
browserify main.js -o bundle.js
```

but if you don't specify `-o`, output goes to stdout. This is a very handy
feature! It means that for example you can pipe to a minifier like uglify in a
very simple and straightforward way:

``` sh
browserify main.js | uglifyjs -cm > bundle.js
```

This way, browserify doesn't need to include uglify by default, unlike webpack.
Users are free to use different minifiers and will not be beholden to whatever
version of uglilify that browserify ships with.

Plus you can make fancier pipelines without mucking about reading browserify
core docs. Want to make both a minified and a minified+gzipped version?

``` sh
browserify main.js | uglifyjs -cm | tee bundle.js | gzip > bundle.js.gz
```

These tricks work with watchify too:

``` sh
watchify main.js -o 'uglifyjs -cm | tee bundle.js | gzip > bundle.js.gz' -dv
```

and factor-bundle:

``` sh
browserify files/*.js \
    -p [ ../ -o 'uglifyjs -cm | tee bundle/`basename $FILE` | gzip > bundle/`basename $FILE`.gz' ] \
    | uglifyjs -cm | tee bundle/common.js | gzip > bundle/common.js.gz
```

Or you can use the API directly.

# transforms instead of loaders

Webpack uses "loaders" to preprocess files, while browserify uses transforms.

In webpack you might do:

``` js
{
    module: {
        loaders: [
            { test: /\.coffee$/, loader: "coffee-loader" }
        ]
    }
}
```

but this configuration applies globally across an entire project. This is
considered rather risky in browserify land and reserved for special occasions.
In browserify, you would do:

``` sh
browserify -t coffeeify main.coffee > bundle.js
```

but this transform would *only* apply to local files, *not* to modules installed
with npm and placed in node_modules/. This is because those modules were written
by other folks with different opinions about how to structure their projects. In
browserify-land, decisions about how to transform source code are made very
locally at the package level, whereas loaders in webpack are global.

Additionally in browserify-land, any package may have a package.json that
specifies special transforms to use. These transforms are applied automatically
and transparently with the reasoning that the people who wrote the code for
those packages know best what transformations are necessary to make the code
work. Webpack takes the opposite opinion: that application developers should be
responsible for all the loader transformations across the entire dependency
graph. I don't think this idea will pan out at scale the way that it already has
in the browserify ecosystem.

Webpack loaders also care about file extensions to an unusual degree and are
trying to make a central registry of file extensions to loaders. In browserify,
file extensions are handled at the individual application and transform level
because transformations might apply to the same file extensions in different
contexts: one to handle [inlining static
assets](https://npmjs.org/package/brfs),
another to [expand file globs](https://www.npmjs.com/package/bulkify).

Handily, transforms can also be configured from both
[package.json](https://github.com/substack/module-deps#packagejson-transformkey),
the api, and the
[command-line](https://github.com/substack/node-browserify#btransformtr-opts).

# inline source maps

In webpack you can do:

```
webpack --devtool inline-source-map main.js bundle.js
```

whereas in browserify you would do:

```
browserify --debug main.js > bundle.js
```

Inline source maps are the default in browserify because they require no
additional configuration about how or where to serve up extra static assets.

# external source maps

In webpack, separate source maps appear with:

```
webpack --devtool eval main.js bundle.js
```

which implicitly creates an external source map file that you will need to
configure to be serve from the appropriate web root.

This can be done in browserify with an external tool,
[exorcist](https://npmjs.org/package/exorcist):

```
browserify --debug main.js | exorcist bundle.js.map > bundle.js
```

This creates a file `bundle.js.map` that `bundle.js` will point at as an
external source map.

# AMD

In webpack, AMD "just works" when the files that webpack needs are hosted in the
proper directory.

In browserify, you can obtain AMD with [deamdify](https://npmjs.org/package/deamdify) or
[browserify-shim](https://npmjs.org/package/browserify-shim).

# fast watching

In webpack lingo this is confusingly called "incremental compilation" and is
built into webpack core with:

```
webpack --watch main.js bundle.js
```

In browserify, you can just do:

```
watchify main.js -o bundle.js -v
```

to watch and also print out a message when a build is complete. Unless something
is very misconfigured, rebuilding with watchify after the first build should
take a few hundred milliseconds at most, similar to webpack.

# css

So many times people keep claiming that browserify "doesn't care about css".
This is true, but very misleading. Browserify *itself* does not concern itself
with css, but has plenty of extensibility points for different approaches toward
modular css to bloom.

Webpack has one solution: put everything into the webpack asset graph.
browserify has many approaches. I think that many different approaches map much
better to the diversity of requirements that people have for building modular
components.

## css transforms

First of all, there are lots of css transforms. Some of them are generic like
[brfs](https://npmjs.org/package/brfs) that you can combine with other libraries
like [insert-css](https://npmjs.org/package/insert-css):

``` js
var fs = require('fs');
var insertcss = require('insert-css');
insertcss(fs.readFileSync(__dirname + '/style.css', 'utf8'));
```

and then just compile with brfs:

```
browserify -t brfs main.js > bundle.js
```

or you can use format-specific css preprocessors such as
[lessify](https://npmjs.org/package/lessify):

``` js
require('./whatever.less');
```

and then:

``` sh
browserify -t lessify main.js > bundle.js
```

## parcelify

parcelify is a very overlooked but powerful answer to handling css in a modular
way. parcelify uses browserify to build a dependency graph and automatically
reads package.json files as necessary to concatenate all the necessary css.

To make a package with css assets, just put:

```
{
  "name" : "my-module",
  "version": "1.5.0",
  "style" : "*.css"
}
```

into the package.json for the module.

Now when you `require('my-module')` elsewhere starting from an entry point
`main.js` and compile with browserify like usual:

``` sh
browserify main.js > bundle.js
```

you'll also be able to run:

``` sh
parcelify main.js -c bundle.css
```

to compile your css all in one big bundle!

There are options to apply css transforms and do file watching too.

## npm-css

You can also use [npm-css](https://www.npmjs.com/package/npm-css) to have
`@import` for css files similarly to `require()` in javascript code:

``` css
@import "typeahead";
@import "./foo.css";

.foo {
  color: red
}
```

which will resolve `typeahead` from `node_modules` and `foo.css` from the same
directory as the css file just like how `require()` behaves.

npm-css doesn't actually have anything to do with browserify at all! It just so
happens to pair nicely for handling css. Instead of a `main` field in
package.json, use a `style` field to specify a css entry point.

## atomify

atomify provides a slightly more opinionated solution, insofar as it's possible
to do that in the browserify ecosystem, for handling both javascript and css. It
can resolve `@import` statements with the node require algorithm and uses
[rework](https://npmjs.org/package/rework) behind the scenes to provide
prefixes, inline images, and variables.

# points of divergence

browserify and webpack disagree one some fundamentals.
browserify prefers:

* more local decisions for better composition
* node and npm compatability
* userland experimentation and diversity instead of a large core

## composability

Browserify takes great pains to compose well at scale across many packages from
many different authors. To do this, it's very important to make decisions
locally instead of globally. When people mouth off that something like webpack
is "more powerful" than browserify, first of all that doesn't mean anything.
Second of all, don't assume that power is always good. The bigger a project gets
and the deeper its dependency graph, the more important structuring effects at
scale becomes. When transforms can operate globally over the entire graph, it's
hard to predict where those transformations could fail or interfere with
existing code. It's still possible to achieve these kinds of global actions with
plugins and global transforms because occasionally nothing else will do, but
ordinary transforms with narrower effect are much more highly encouraged.

## overloading require

webpack encorages overloading `require()` to mean something very different from
what it means in node:

``` js
require("coffee!./cup.coffee");
```

This will make it very hard to reuse your code in anything that is not webpack,
particularly node.

browserify will never encourage this, opting for simple node-style require() and
node compatability where possible

## node and npm compatability

browserify puts in a lot of tiny, subtle features so that modules from npm with
mostly "just work". The module lookup algorithm is exactly the same, including
tiny things like the order of operations and default extensions like `.json`.
Node core modules that make sense in a browser context like `path` and `util`
also just work without any special configuration.

According to some sophisticated static analysis done by
[airportyh](https://github.com/airportyh), around half of the packages on npm
are likely to just work with browserify. You can search this subset of packages
on [browserifysearch.org](http://browserifysearch.org/).

# in closing

Be wary of [bullet-point engineering](https://en.wikipedia.org/wiki/Bullet-point_engineering).

Comparing technologies strictly on what checks all the boxes might seem like it
will solve your problems faster, but lumping too many features together is a
recipe for scope creep and inflexibility later on.

# read more

* http://mattdesl.svbtle.com/browserify-vs-webpack
* https://github.com/substack/browserify-handbook
